<?php
namespace x\my;

class Cookie {
	/**
	 * 配置参数
	 * @var array
	 */
	protected $config = [
		// cookie 名称前缀
		'prefix' => '',
		// cookie 保存时间
		'expire' => 0,
		// cookie 保存路径
		'path' => '/',
		// cookie 有效域名
		'domain' => '',
		//  cookie 启用安全传输
		'secure' => false,
		// httponly设置
		'httponly' => false,
		// 是否使用 setcookie
		'setcookie' => true,
		'dbtype' => false, #false,表示不入库
	];

	public function init($prefix = '', $dbtype = false) {
		$this->config['prefix'] = $prefix;
		if ($this->config['httponly']) {
			ini_set('session.cookie_httponly', 1);
		}
		$this->dbtype = $dbtype;
		return $this;
	}

	/**
	 * 设置或者获取cookie作用域（前缀）
	 * @access public
	 * @param  string $prefix
	 * @return string|void
	 */
	public function prefix($prefix = '') {
		if (empty($prefix)) {
			return $this->config['prefix'];
		}

		$this->config['prefix'] = $prefix;
	}

	/**
	 * Cookie 设置、获取、删除
	 *
	 * @access public
	 * @param  string $name  cookie名称
	 * @param  mixed  $value cookie值
	 * @param  mixed  $option 可选参数 可能会是 null|integer|string
	 * @return void
	 */
	public function set($name, $value = '', $option = null) {
		// 参数设置(会覆盖黙认设置)
		if (!is_null($option)) {
			if (is_numeric($option)) {
				$option = ['expire' => $option];
			} elseif (is_string($option)) {
				parse_str($option, $option);
			}

			$config = array_merge($this->config, array_change_key_case($option));
		} else {
			$config = $this->config;
		}

		$name = $config['prefix'] . $name;

		// 设置cookie
		if (is_array($value)) {
			array_walk_recursive($value, [$this, 'jsonFormatProtect'], 'encode');
			$value = 'think:' . json_encode($value);
		}

		$expire = !empty($config['expire']) ? $_SERVER['REQUEST_TIME'] + intval($config['expire']) : 0;
		//过滤cookie
		$value = htmlspecialchars($value);
		if ($config['setcookie']) {
			setcookie($name, $value, $expire, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
		}
		if ($this->dbtype) {
			$this->intoDb($name, $value);
		}

		$_COOKIE[$name] = $value;
	}
	/**
	 * cookie值插入数据库
	 * @param  [type] $name  [description]
	 * @param  [type] $value [description]
	 * @return [type]        [description]
	 */
	public function intoDb($name, $value) {
		$db = db();
		$db->insert('cookie', ['ip' => ip(), 'token' => $name, 'code' => $value, 'type' => $this->dbtype, 'create_time' => time()]);
	}

	/**
	 * 永久保存Cookie数据
	 * @access public
	 * @param  string $name  cookie名称
	 * @param  mixed  $value cookie值
	 * @param  mixed  $option 可选参数 可能会是 null|integer|string
	 * @return void
	 */
	public function forever($name, $value = '', $option = null) {
		if (is_null($option) || is_numeric($option)) {
			$option = [];
		}

		$option['expire'] = 315360000;

		$this->set($name, $value, $option);
	}

	/**
	 * 判断Cookie数据
	 * @access public
	 * @param  string        $name cookie名称
	 * @param  string|null   $prefix cookie前缀
	 * @return bool
	 */
	public function has($name, $prefix = null) {
		!isset($this->init) && $this->init();

		$prefix = !is_null($prefix) ? $prefix : $this->config['prefix'];
		$name = $prefix . $name;

		return isset($_COOKIE[$name]);
	}

	/**
	 * Cookie获取
	 * @access public
	 * @param  string        $name cookie名称 留空获取全部
	 * @param  string|null   $prefix cookie前缀
	 * @return mixed
	 */
	public function get($name = '', $prefix = null) {
		$prefix = !is_null($prefix) ? $prefix : $this->config['prefix'];
		$key = $prefix . $name;

		if ('' == $name) {
			if ($prefix) {
				$value = [];
				foreach ($_COOKIE as $k => $val) {
					if (0 === strpos($k, $prefix)) {
						$value[$k] = $val;
					}
				}
			} else {
				$value = $_COOKIE;
			}
		} elseif (isset($_COOKIE[$key])) {
			$value = $_COOKIE[$key];

			if (0 === strpos($value, 'think:')) {
				$value = substr($value, 6);
				$value = json_decode($value, true);
				array_walk_recursive($value, [$this, 'jsonFormatProtect'], 'decode');
			}
		} else {
			$value = null;
		}
		return $value;
	}

	/**
	 * Cookie删除
	 * @access public
	 * @param  string        $name cookie名称
	 * @param  string|null   $prefix cookie前缀
	 * @return void
	 */
	public function delete($name, $prefix = null) {
		$config = $this->config;
		$prefix = !is_null($prefix) ? $prefix : $config['prefix'];
		$name = $prefix . $name;

		if ($config['setcookie']) {
			setcookie($name, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
		}

		// 删除指定cookie
		unset($_COOKIE[$name]);
	}

	/**
	 * Cookie清空
	 * @access public
	 * @param  string|null $prefix cookie前缀
	 * @return void
	 */
	public function clear($prefix = null) {
		// 清除指定前缀的所有cookie
		if (empty($_COOKIE)) {
			return;
		}
		// 要删除的cookie前缀，不指定则删除config设置的指定前缀
		$config = $this->config;
		$prefix = !is_null($prefix) ? $prefix : $config['prefix'];
		if ($prefix) {
			// 如果前缀为空字符串将不作处理直接返回
			foreach ($_COOKIE as $key => $val) {
				if (0 === strpos($key, $prefix)) {
					if ($config['setcookie']) {
						setcookie($key, '', $_SERVER['REQUEST_TIME'] - 3600, $config['path'], $config['domain'], $config['secure'], $config['httponly']);
					}
					unset($_COOKIE[$key]);
				}
			}
		}

		return;
	}

	private function jsonFormatProtect(&$val, $key, $type = 'encode') {
		if (!empty($val) && true !== $val) {
			$val = 'decode' == $type ? urldecode($val) : urlencode($val);
		}
	}

}
